/**
 * 滑入
 * slidingin
 * 
 * 滑动
 * slidingmove
 * 
 * 滑出
 * slidingout
 * 
 * 已知问题：
 * 滑动太快会捕获不到事件
 */

import { menu } from '../../../app/decorator';

const { ccclass } = cc._decorator;

@ccclass
@menu(__filename, '滑动触摸')
export default class TouchSliding extends cc.Component {
    private _target: cc.Node = null;

    onLoad() {
        this.node.on('touchstart', this._onTouchStart, this, true);
        this.node.on('touchmove', this._onTouchMove, this, true);
        this.node.on('touchend', this._onTouchEnd, this, true);
        this.node.on('touchcancel', this._onTouchCancel, this, true);

        this.node['_hitTest'] = (...args) => {
            const children = this.node.children;
            for (let index = 0; index < children.length; index++) {
                const node = children[index];
                if (node['_hitTest'].call(node, ...args)) {
                    return true;
                }
            }
            return false;
        };
    }

    private _changeTarget(target, eventName) {
        // slidingmove过程中更换节点，向新节点发射slidingin事件，向老节点发射slidingout事件
        if (target !== this._target && eventName === 'slidingmove') {
            this._target && this._target.emit('slidingout');
            target && target.emit('slidingin');
        }

        this._target = target;
        this._target && this._target.emit(eventName);
    }

    private _getChildByTouch(event) {
        let pos = event.getLocation();
        let children = this.node.children;
        for (let index = children.length - 1; index >= 0; index--) {
            let node = children[index];
            let rect = node.getBoundingBoxToWorld();
            if (rect.contains(pos)) {
                return node;
            }
        }
        return null;
    }

    private _onTouchStart(event) {
        this._changeTarget(this._getChildByTouch(event), 'slidingin');
    }

    private _onTouchMove(event) {
        this._changeTarget(this._getChildByTouch(event), 'slidingmove');
    }

    private _onTouchEnd(event) {
        this._changeTarget(this._getChildByTouch(event), 'slidingout');
    }

    private _onTouchCancel(event) {
        this._changeTarget(this._getChildByTouch(event), 'slidingout');
    }
}
